iT邦幫忙

2024 iThome 鐵人賽

DAY 16
2
DevOps

後 Grafana 時代的自我修養系列 第 16

後 Grafana 時代的第十六天 - Gafana IaC 實戰 - Organization、Team、User

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20240930/20149562mWknTrzcmw.png

前言

在前面的章節中,我們已經深入探討了實現 Grafana IaC 相關的核心概念和注意事項,這為後續的實作打下了良好的基礎。這也呼應了本系列文章的主題,隨著對 Grafana 應用場景的理解越來越深入,所需掌握的技能和概念也需要全面提升。現在,我們將逐步切入 Terraform 中 Grafana IaC 的實作部分。

此前,我們提到將 Terraform Grafana Provider 的資源分為三個部分來介紹,而接下來我們就要正式從 OrganizationTeamUser 之間的設計開始著手,逐步構建出完整的 Grafana IaC 解決方案。

Organization 和 Team、User 的關係

在 Grafana 中,我們可以將組織用戶管理的資源簡單區分為 Organization、Team 和 User 三種維度,瞭解了這之間的關係後,有助於我們從零搭建起整個 Grafana 服務。

以下是這三者關係圖:

https://ithelp.ithome.com.tw/upload/images/20240930/20149562D3OQ5ja281.png

說明:

  • Organization 與 User 是多對多的關係,表示一個組織可以包含多個使用者,而一個使用者可以屬於多個組織。
  • Team 與 User 是多對多的關係,表示一個團隊可以包含多個使用者,而一個使用者可以屬於多個團隊。
  • Organization 與 Team 是一對多的關係,表示一個組織可以有多個團隊,但每個團隊屬於一個組織。

這個圖示反映了 Grafana 中 Organization 和 Team、User 之間的關係。

Organization

Organization 是 Grafana 中組織的單位,可以理解為一個組織的集合,例如:公司、部門、團隊等。對於不同的組織,我們可以設定不同的權限和設定。這也是 Grafana 資源中最頂層的資源。

Grafana 建立後,會自動生成一個預設的 Organization,名稱為 Main Org.,我們也可以在 Terraform 中建立新的 Organization,如果我們不指定的話將會依據提供的 Grafana Provider 帳號所在的 Organization 為預設值。

在本篇文章中,我們將會遵循官方最佳實踐建議,不建立新的 Organization,而是使用預設 org_id 為 1 的 Organization。所以我們必須域現在 Terraform 中執行以下指令 import 現有的 Organization。

將現有的 Organization 匯入到 Terraform 中:

terraform import grafana_organization.default 1  # 1 為 org_id

resource "grafana_organization" "default" {
  name         = "Main Org."
  admin_user   = "admin"
  create_users = false
  admins = [
  ]
  editors = [
  ]
  viewers = [
  ]
}

Team

在 Grafana 中,Team 是組織的子資源,可以理解為一個團隊的集合,且實務上的 Team 可以對應到我們在公司內部的部門、小組、團隊等。所以在這裡我們不以 Organization 作為劃分,而是以 Team 這個維度來進行實現。

Note: 在目前的 Grafana Provider 版本中,Team 中的角色權限並還不支援 admin的設定,每個 Team 的成為預設都是 Member。

https://ithelp.ithome.com.tw/upload/images/20240930/20149562guAzLbsTW9.png

User

在 Grafana 中,User 是組織的子資源,可以理解為一個使用者的集合,可以對應到公司的員工、使用者等。在建立 User 時,我們更多的會去控制 User 的權限,例如:可以加入哪個 Team 或可以存取的 Organization、Folder 等。

Note: 如果團隊中選擇使用 SSO 或 Oauth2 登入,則不會有 User 的資源,而是會將 User 的資源交由 SSO 或 Oauth2 的 Provider 進行管理。

https://ithelp.ithome.com.tw/upload/images/20240930/20149562vpwaFt9hSI.png

此外,我們也要視實際情況將預設的 Admin User(如果有的話) 匯入到 Terraform 中:

terraform import grafana_user.default 1  # 1 為 user_id

resource "grafana_user" "default" {
  email = "admin@example.com"
  name = "admin"
  login = "admin"
  password = "admin"
  is_admin = true
}

實戰演練

現在,我們已經瞭解了 Organization、Team 和 User 之間的關係,接下來我們將結合先前所提到的全域動態生成資源的概念搭配三者之間的關係,實作我們的 Grafana IaC 解決方案。

設計全域資源結構

locals {
  users = {
    "john@example.com" = {
      name = "John"
      role = "Admin"
      is_admin = false
    }
    "alice@example.com" = {
      name = "Alice"
      role = "Editor"
      is_admin = false
    }
    "bob@example.com" = {
      name = "Bob"
      role = "Viewer"
      is_admin = false
    }
    "carol@example.com" = {
      name = "Carol"
      role = "Editor"
      is_admin = false
    }
  }
  teams = {
    "Engineering" = {
      members = ["john@example.com", "alice@example.com"]
    }
    "Marketing" = {
      members = ["bob@example.com", "carol@example.com"]
    }
  }
}

在這裡我們定義了全域的變數,包含了 users 和 teams 兩個變數,分別用來存放使用者和團隊的資訊。在 users 中,我們可以看到我們使用了映射(map)的方式來存放使用者的資訊,並且在後續的資源中我們會透過 for_each 的方式來迭代這些使用者。而在 teams 中,我們同樣使用了映射(map)的方式來存放團隊的資訊,並且在後續的資源中我們會透過 for_each 的方式來迭代這些團隊。

實際建立資源

# 預設的 Organization
resource "grafana_organization" "default" {
  name         = "Main Org."
  admin_user   = grafana_user.default.name
  create_users = false
  # 使用 grafana_user.users 資源來設置組織的管理員、編輯者和查看者
  # 這樣可以確保只有已經創建的用戶被添加到組織中
  admins  = [for user in grafana_user.users : user.email if local.users[user.email].role == "Admin"]
  editors = [for user in grafana_user.users : user.email if local.users[user.email].role == "Editor"]
  viewers = [for user in grafana_user.users : user.email if local.users[user.email].role == "Viewer"]

  depends_on = [grafana_team.teams, grafana_user.users]
}

# 預設的 Admin User
resource "grafana_user" "default" {
  email = "admin@example.com"
  name = "admin"
  login = "admin"
  password = "admin"  # 考慮使用更安全的方式設置密碼
  is_admin = true
}

# 建立使用者
resource "grafana_user" "users" {
  for_each = local.users

  email    = each.key
  name     = each.value.name
  login    = split("@", each.key)[0]
  password = "default-password"  # 考慮使用更安全的方式設置密碼
  is_admin = each.value.is_admin
}

# 建立團隊
resource "grafana_team" "teams" {
  for_each = local.teams

  # org_id = grafana_organization.default.id
  name   = each.key
  members = each.value.members

  depends_on = [grafana_user.users]
}

接著就讓我們實際執行指令建立資源:

terraform init
terraform apply
---
Terraform will perform the following actions:

  # grafana_organization.default will be updated in-place
  ~ resource "grafana_organization" "default" {
      ~ admins               = [
          + "john@example.com",
        ]
      ~ editors              = [
          + "alice@example.com",
          + "carol@example.com",
        ]
        id                   = "1"
        name                 = "Main Org."
      ~ viewers              = [
          + "bob@example.com",
        ]
        # (4 unchanged attributes hidden)
    }

  # grafana_team.teams["Engineering"] will be created
  + resource "grafana_team" "teams" {
      + id      = (known after apply)
      + members = [
          + "alice@example.com",
          + "john@example.com",
        ]
      + name    = "Engineering"
      + team_id = (known after apply)
    }

  # grafana_team.teams["Marketing"] will be created
  + resource "grafana_team" "teams" {
      + id      = (known after apply)
      + members = [
          + "bob@example.com",
          + "carol@example.com",
        ]
      + name    = "Marketing"
      + team_id = (known after apply)
    }

  # grafana_user.users["alice@example.com"] will be created
  + resource "grafana_user" "users" {
      + email    = "alice@example.com"
      + id       = (known after apply)
      + is_admin = false
      + login    = "alice"
      + name     = "Alice"
      + password = (sensitive value)
      + user_id  = (known after apply)
    }

  # grafana_user.users["bob@example.com"] will be created
  + resource "grafana_user" "users" {
      + email    = "bob@example.com"
      + id       = (known after apply)
      + is_admin = false
      + login    = "bob"
      + name     = "Bob"
      + password = (sensitive value)
      + user_id  = (known after apply)
    }

  # grafana_user.users["carol@example.com"] will be created
  + resource "grafana_user" "users" {
      + email    = "carol@example.com"
      + id       = (known after apply)
      + is_admin = false
      + login    = "carol"
      + name     = "Carol"
      + password = (sensitive value)
      + user_id  = (known after apply)
    }

  # grafana_user.users["john@example.com"] will be created
  + resource "grafana_user" "users" {
      + email    = "john@example.com"
      + id       = (known after apply)
      + is_admin = false
      + login    = "john"
      + name     = "John"
      + password = (sensitive value)
      + user_id  = (known after apply)
    }

Plan: 6 to add, 1 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

Apply complete! Resources: 6 added, 1 changed, 0 destroyed.

在這個 Terraform 設定中,我們利用了動態和抽象的方法來管理 Grafana 的組織結構。讓我們深入了解這個設定的主要部分:

  • Organization:
    我們在預設的 Grafana 組織 "Main Org." 中,透過使用 grafana_organization 資源來設置組織的管理員、編輯者和查看者。這樣可以確保只有已經創建的用戶被添加到組織中。

https://ithelp.ithome.com.tw/upload/images/20240930/20149562UyRp16DIN0.png

  • User:
    我們定義了一個預設的管理員使用者,並使用 for_each 迴圈來動態建立多個一般使用者。這種方法允許我們靈活地新增或刪除使用者,只需更新 local.users 變數即可。每個使用者都被賦予了特定的角色(Admin、Editor 或 Viewer),這直接對應到他們在組織中的權限。

https://ithelp.ithome.com.tw/upload/images/20240930/20149562V0NCfWmUwj.png

  • Team:
    我們使用類似的 for_each 迴圈來建立團隊。每個團隊都有一個名稱和一組成員。這種結構使得新增新團隊或修改現有團隊的成員變得非常簡單。

https://ithelp.ithome.com.tw/upload/images/20240930/20149562YGqeII4luN.png

https://ithelp.ithome.com.tw/upload/images/20240930/20149562mJ2k5Oskmq.png

  • Permission:
    透過在組織資源中使用條件陳述式(if local.users[user.email].role == "Admin"等),我們可以根據使用者的預定義角色自動設定他們在組織中的權限。這確保了權限的一致性,並減少了手動設定錯誤的可能性。

https://ithelp.ithome.com.tw/upload/images/20240930/20149562Hrgs5WDqgj.png

  • Dependency:
    我們使用 depends_on 參數來確保資源建立的正確順序。例如,團隊的建立相依於使用者的建立,這樣可以避免引用不存在的使用者。

這種設定方法的主要優勢在於其靈活性和可擴展性。透過修改 local.users 和 local.teams 變數,我們可以輕鬆地新增、刪除或修改使用者和團隊,而無需更改核心的 Terraform 程式碼。這不僅簡化了管理過程,還提高了設定的可讀性和可維護性。

總結

在本篇文章中,我們深入探討了如何使用 Terraform 來實現 Grafana IaC 的實作。這種方法不僅提高了管理效率,還大大增強了系統的可擴展性和可維護性。

我們首先詳細介紹了 Grafana 中 Organization、Team 和 User 之間的複雜關係建立了穩固的概念基礎。接著,我們精心設計了一個靈活且強大的全域資源結構,這個結構能夠適應各種規模的組織需求。
在實作階段,我們逐步由淺入深地展示了如何使用 Terraform 的進階功能,如 for_each 迴圈和判斷式,來動態建立和管理資源,並且強調了如何透過 local 變數來實現設定的集中管理和易於修改。

接下來,就讓我們繼續深入到下一個篇章,實際搭建起更完整的 Grafana IaC 吧。


References:


上一篇
後 Grafana 時代的第十五天 - Gafana IaC 實戰 - 使用 Terraform 動態產生 Grafana 資源
下一篇
後 Grafana 時代的第十七天 - Gafana IaC 實戰 - DataSource
系列文
後 Grafana 時代的自我修養31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言